package com.google.code.sharecontent.test.readmp3;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException;
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException;
import org.jaudiotagger.audio.mp3.MP3File;
import org.jaudiotagger.tag.TagException;
import org.jaudiotagger.tag.TagField;
import org.jaudiotagger.tag.id3.valuepair.TextEncoding;

/**
 * Основное окно программы
 * 
 * @author marat
 * 
 */
public class MainFrame extends JFrame {

	private static final long serialVersionUID = 7613011516680903689L;

	private List<Mp3Info> infos = new ArrayList<Mp3Info>();
	private JTextField filename = new JTextField(), dir = new JTextField();
	private JButton open = new JButton("Open");
	private JButton start2 = new JButton("Parse 2");
	private JButton startUrl = new JButton("Parse Url");
	private JButton startUrl2 = new JButton("Parse Url 2");

	// Object[][] data;
	JTable table;

	public MainFrame(String title) {
		super(title);
		this.setSize(800, 500);
		this.setLayout(new BorderLayout());
		JPanel panelNorth = new JPanel();
		panelNorth.setLayout(new FlowLayout(FlowLayout.LEFT));
		this.add(panelNorth, BorderLayout.NORTH);
		panelNorth.add(dir);
		panelNorth.add(open);
		panelNorth.add(start2);
		panelNorth.add(startUrl);
		panelNorth.add(startUrl2);
		dir.setEditable(true);
		dir.setColumns(30);

		table = new JTable(new Mp3TableModel(infos));
		this.add(new JScrollPane(table), BorderLayout.CENTER);

		open.addActionListener(new OpenL());
		start2.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				parseFolder(2);
			}
		});
		// start2.setEnabled(false);

		startUrl.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				parseUrl();
			}
		});

		startUrl2.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Thread thr = new Thread(new Runnable() {
					public void run() {
						downloadAndParseMp3();
					}
				});
				thr.setPriority(thr.getPriority() - 1);
				thr.start();
			}
		});

		dir.setText("ftp://odcws014.russia.local/music/Brainstorm");
		// dir.setText("http://rusdt0105.russia.local/music/%D0%A7%D0%B0%D0%B9%D1%84/01-Realniy%20mir%20%281996%29/");
		// dir.setText("C:/marat/music/Чайф/01-Realniy mir (1996)/");
		// ftp://odcws014.russia.local/music/
		// http://192.168.10.102/music/5nizza/
	}

	public void downloadAndParseMp3() {
		if (infos != null && infos.size() > 0) {
			for (Mp3Info info : infos) {
				try {
					HttpClient client = new HttpClient();
					GetMethod method = new GetMethod(info.getUrl());
					System.out.println("started download " + info.getUrl());
					int status = client.executeMethod(method);

					if (status != HttpStatus.SC_OK) {
						System.err.println("Method failed: "
								+ method.getStatusLine());
						return;
					}
					String paramDate = null;
					String paramLastModified = null;
					Integer paramContentLength = null;
					Header header;
					if ((header = method.getResponseHeader("Date")) != null) {
						paramDate = header.getValue();
					}
					if ((header = method.getResponseHeader("Last-Modified")) != null) {
						paramLastModified = header.getValue();
					}
					if ((header = method.getResponseHeader("Content-Length")) != null) {
						paramContentLength = new Integer(header.getValue());
					}
					info.setParamDate(paramDate);
					info.setParamLastModified(paramLastModified);
					info.setSize(paramContentLength);

					String tempMp3 = System.getProperty("java.io.tmpdir")
							+ File.separator + info.getFileName();
					System.out.println("File " + tempMp3);
					File tempMp3File = new File(tempMp3);
					FileOutputStream fos = new FileOutputStream(tempMp3File);
					InputStream is = method.getResponseBodyAsStream();
					int b;
					while ((b = is.read()) != -1) {
						fos.write(b);
					}
					fos.flush();
					fos.close();
					System.out.println("Saved to " + tempMp3);
					System.out.println(System.getProperty("java.io.tmpdir"));

					info = parseMp3_method2(info, tempMp3File);
					System.out.println("Parsed file " + tempMp3);
					boolean del = tempMp3File.delete();
					System.out.println("File has deleted " + del);

				} catch (HttpException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

				table.updateUI();
			}
		}
	}

	Set<String> urlsAll = new HashSet<String>();
	List<String> urlQuery = new ArrayList<String>();
	String baseUrl = "";

	private void addDirectoryToQuery(String url) {
		// нельзя подниматься выше базового урла
		if (url != null && url.indexOf(baseUrl) > -1) {
			if (!urlsAll.contains(url)) {
				urlQuery.add(url);
				urlsAll.add(url);
				System.out.println("add new url " + url);
			}
		}
	}

	Set<String> filesAll = new HashSet<String>();

	private void addFilesToQuery(String url, String fileName) {
		// нельзя подниматься выше базового урла
		if (url != null && url.indexOf(baseUrl) > -1) {
			if (!filesAll.contains(url)) {
				filesAll.add(url);
				System.out.println("add new file " + url);
				Mp3Info info = new Mp3Info();
				info.setUrl(url);
				info.setFileName(fileName);
				infos.add(info);
			}
		}
	}

	private void parseUrl() {
		String protocol = "";
		try {
			URL url;
			url = new URL(dir.getText());
			protocol = url.getProtocol();
			if ("http".equals(protocol)) {
				addDirectoryToQuery(baseUrl = dir.getText());
				while (urlQuery.size() > 0) {
					parseUrl(urlQuery.get(0));
					urlQuery.remove(0);
				}
			}
			if ("ftp".equals(protocol)) {
				parseFtp(url);
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
		table.updateUI();
	}

	private void parseFtp(URL url) {
		// Connect and logon to FTP Server
		FTPClient ftp = new FTPClient();
		try {
			ftp.connect(url.getHost());
			ftp.login("anonymous", "anonymous");
			ftp.setControlEncoding("UTF-8");
			System.out.println("Connected to " + url.getHost() + ".");
			System.out.print(ftp.getReplyString());
			// List the files in the directory
			String folder = url.getPath();
			
			parseFtpDirectory(ftp, folder);

			// Logout from the FTP Server and disconnect
			ftp.logout();
			ftp.disconnect();

		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	private void parseFtpDirectory(FTPClient ftp, String folder)
			throws IOException {
		ftp.changeWorkingDirectory(folder);
		FTPFile[] files = ftp.listFiles();
		System.out.println("Number of files in dir: " + files.length);
		DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
		for (int i = 0; i < files.length; i++) {
			Date fileDate = files[i].getTimestamp().getTime();
			// Download a file from the FTP Server
			System.out.print(files[i].getName());
			if (files[i].isFile()) {
				System.out.print("\t File");
			}
			System.out.print("\t" + files[i].getSize());
			System.out.print("\t"+ df.format(fileDate));
			System.out.println();
			if (files[i].isDirectory()) {
				System.out.print("\t Directory");
				parseFtpDirectory(ftp, folder+File.separator+files[i].getName());
			}
			/*
			 * File file = new File( destinationFolder + File.separator +
			 * files[ i ].getName() ); FileOutputStream fos = new
			 * FileOutputStream( file ); ftp.retrieveFile( files[ i
			 * ].getName(), fos ); fos.close(); file.setLastModified(
			 * fileDate.getTime() );
			 */
		}
	}

	private void parseUrl(String url) {
		try {
			System.out.println("open url " + url);
			HttpClient client = new HttpClient();
			GetMethod method = new GetMethod(url);
			int status = client.executeMethod(method);

			if (status != HttpStatus.SC_OK) {
				System.err.println("Method failed: " + method.getStatusLine());
				return;
			}

			String result = method.getResponseBodyAsString();
			// парсим
			int b;
			int e;
			while ((b = result.indexOf("<li>")) > -1
					&& (e = result.indexOf("</li>", b)) > b) {
				String temp = result.substring(b + "<li>".length(), e);
				result = result.substring(e);
				// System.out.println(temp);
				GetMethod method2 = new GetMethod(url);
				int ab;
				int ae;
				if ((ab = temp.indexOf("href=\"")) > -1
						&& (ae = temp.indexOf("\"", ab + "href=\"".length())) > ab) {
					String fileName = temp.substring(ab + "href=\"".length(),
							ae);
					if (fileName.matches("/$")) {
						continue;
					}
					if (fileName.matches(".*/$")) {
						if (fileName.matches("^/.*")) {
							method2.setPath(fileName);
						} else {
							method2.setPath(method2.getPath() + fileName);
						}
						addDirectoryToQuery(method2.getURI().toString());
					} else {
						// file
						if (fileName.toLowerCase().matches(".*\\.mp3")) {
							method2.setPath(method2.getPath() + fileName);
							addFilesToQuery(method2.getURI().toString(),
									fileName);
						}
					}
				}
			}

			// System.out.println(result);
		} catch (Exception e) {
			System.out.println(e.getLocalizedMessage());
		}
	}

	private void parseFolder(int methodId) {
		File directory = new File(dir.getText());
		FilenameFilter filter = new Mp3Filter();
		if (directory.isDirectory()) {
			File[] files = directory.listFiles(filter);
			if (files != null && files.length > 0) {
				for (File file : files) {
						System.out.println("file: " + file.getName());
						switch (methodId) {
						case 2:
							infos.add(parseMp3_method2(file));
							break;
						}

				}
			}
			table.updateUI();
		}
	}

	private Mp3Info parseMp3_method2(Mp3Info info, File file) {
		try {
			// MP3File mp3file = new MP3File(file, MP3File.LOAD_ALL, true);
			MP3File mp3file = new MP3File(file, MP3File.LOAD_ALL, true,
					"Cp1251");
			boolean hasID3v2Tag = mp3file.hasID3v2Tag();
			boolean hasID3v1Tag = mp3file.hasID3v1Tag();

			// title
			if (hasID3v2Tag) {
				if (mp3file.getID3v2Tag().getFirstTitle() != null
						&& mp3file.getID3v2Tag().getFirstTitle().length() > 0) {
					info.setTitle(mp3file.getID3v2Tag().getFirstTitle());
				}
				if (mp3file.getID3v2Tag().getArtist() != null
						&& mp3file.getID3v2Tag().getArtist().size() > 0) {
					info.setArtist(fieldsToString(mp3file.getID3v2Tag()
							.getArtist()));
				}
				if (mp3file.getID3v2Tag().getAlbum() != null
						&& mp3file.getID3v2Tag().getAlbum().size() > 0) {
					info.setAlbum(fieldsToString(mp3file.getID3v2Tag()
							.getAlbum()));
				}
				if (mp3file.getID3v2Tag().getGenre() != null
						&& mp3file.getID3v2Tag().getGenre().size() > 0) {
					info.setGenre(fieldsToString(mp3file.getID3v2Tag()
							.getGenre()));
				}
				if (mp3file.getID3v2Tag().getIdentifier() != null) {
					info.setIdentifier(mp3file.getID3v2Tag().getIdentifier());
				}
				if (mp3file.getID3v2Tag().getTrack() != null
						&& mp3file.getID3v2Tag().getTrack().size() > 0) {
					info.setTrack(fieldsToString(mp3file.getID3v2Tag()
							.getTrack()));
				}
				if (mp3file.getID3v2Tag().getYear() != null
						&& mp3file.getID3v2Tag().getYear().size() > 0) {
					info
							.setYear(fieldsToString(mp3file.getID3v2Tag()
									.getYear()));
				}
			}
			if (hasID3v1Tag) {
				if (mp3file.getID3v1Tag().getFirstTitle() != null
						&& mp3file.getID3v1Tag().getFirstTitle().length() > 0) {
					info.setTitle(mp3file.getID3v1Tag().getFirstTitle());
				}
				// Artist
				if (mp3file.getID3v1Tag().getArtist() != null
						&& mp3file.getID3v1Tag().getArtist().size() > 0) {
					info.setArtist(fieldsToString(mp3file.getID3v1Tag()
							.getArtist()));
				}
				// Album
				if (mp3file.getID3v1Tag().getAlbum() != null
						&& mp3file.getID3v1Tag().getAlbum().size() > 0) {
					info.setAlbum(fieldsToString(mp3file.getID3v1Tag()
							.getAlbum()));
				}
				// Genre
				if (mp3file.getID3v1Tag().getGenre() != null
						&& mp3file.getID3v1Tag().getGenre().size() > 0) {
					info.setGenre(fieldsToString(mp3file.getID3v1Tag()
							.getGenre()));
				}
				// Identifie
				if (mp3file.getID3v1Tag().getIdentifier() != null) {
					info.setIdentifier(mp3file.getID3v1Tag().getIdentifier());
				}
				// Track
				/*
				 * else if (mp3file.hasID3v1Tag() &&
				 * mp3file.getID3v1Tag().getTrack() != null &&
				 * mp3file.getID3v1Tag().getTrack().size()>0) {
				 * info.setTrack(fieldsToString
				 * (mp3file.getID3v1Tag().getTrack())); }
				 */// throw new
				// UnsupportedOperationException("ID3v10 cannot store track numbers");
				// Year
				if (mp3file.getID3v1Tag().getYear() != null
						&& mp3file.getID3v1Tag().getYear().size() > 0) {
					info
							.setYear(fieldsToString(mp3file.getID3v1Tag()
									.getYear()));
				}
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (TagException e) {
			e.printStackTrace();
		} catch (ReadOnlyFileException e) {
			e.printStackTrace();
		} catch (InvalidAudioFrameException e) {
			e.printStackTrace();
		}

		return info;
	}

	private Mp3Info parseMp3_method2(File file) {
		Mp3Info info = new Mp3Info();
		return parseMp3_method2(info, file);
	}

	private String fieldsToString(List<TagField> list) {
		StringBuffer sb = new StringBuffer();
		if (list != null && list.size() > 0) {
			for (TagField field : list) {
				if (sb.length() > 0) {
					sb.append(", ");
				}
				sb.append(field.toString());
			}
		}
		return sb.toString();
	}

	class Mp3Filter implements FilenameFilter {
		public boolean accept(File dir, String name) {
			return (name.endsWith(".mp3"));
		}
	}

	class OpenL implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			JFileChooser c = new JFileChooser();
			// Demonstrate "Open" dialog:
			int rVal = c.showOpenDialog(MainFrame.this);
			if (rVal == JFileChooser.APPROVE_OPTION) {
				filename.setText(c.getSelectedFile().getName());
				dir.setText(c.getCurrentDirectory().toString());
			}
			if (rVal == JFileChooser.CANCEL_OPTION) {
				filename.setText("You pressed cancel");
				dir.setText("");
			}
		}
	}

}
